package ru.amse.tsyganov.jumleditor.view;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;

import ru.amse.tsyganov.jumleditor.commands.Command;
import ru.amse.tsyganov.jumleditor.commands.CommandFactory;
import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;

public abstract class StateView<T extends State> extends ViewElement<T> {
	private int stateViewX;
	private int stateViewY;
	private int stateViewWidth = 90;
	private int stateViewHeight = 60;
	
	private List<ActivePoint> points;
		
	public StateView() {
		points = createActivePoints();
	}
	
	public int getX() {
		return stateViewX;
	}
	
	public void setX(int x) {
		this.stateViewX = x;
	}
	
	public int getY() {
		return stateViewY;
	}
	
	public void setY(int y) {
		this.stateViewY = y;
	}
	
	public int getWidth() {
		return stateViewWidth;
	}
	
	public void setWidth(int newWidth) {
		if (newWidth < 0) {
			throw new IllegalArgumentException();
		}
		
		this.stateViewWidth = newWidth;
	}
	
	public int getHeight() {
		return stateViewHeight;
	}
	
	public void setHeight(int newHeight) {
		if (newHeight < 0) {
			throw new IllegalArgumentException();
		}
		
		this.stateViewHeight = newHeight;
	}
	
	public int getCenterX() {
		return getX() + getWidth()/2;
	}
	
	public int getCenterY() {
		return getY() + getHeight()/2;
	}
	
	public Point getCenter() {
		return new Point(getCenterX(), getCenterY());
	}
	
	public Rectangle getRectangle() {
		return new Rectangle(stateViewX, stateViewY, stateViewWidth, stateViewHeight);
	}
	
	@Override
	public void accept(Visitor v) {
		v.visitStateView(this);
		for (Transition t : getModel().getStateVertex().getOutgoing()) {
			TransitionView<? extends Transition> transitionView = 
				ModelViewMap.map.getTransitionsMap().get(t);
			transitionView.accept(v);
		}
	}
	
	@Override
	public final void paint(GC gc) {
		paintFigure(gc);
		
		if (SelectedItems.items.selectedStates.contains(this)) {
			gc.setForeground(new Color(null, new RGB(0,0,0)));
			gc.setLineWidth(2);
			gc.drawRectangle(getRectangle());
			gc.setLineWidth(1);
			paintActivePoints(gc);
		}
		
		for (Transition t : getModel().getStateVertex().getOutgoing()) {
			TransitionView<? extends Transition> transitionView = 
				ModelViewMap.map.getTransitionsMap().get(t);
			transitionView.paint(gc);
		}		
		
		for (Transition t : getModel().getStateVertex().getIncoming()) {
			TransitionView<? extends Transition> transitionView = 
				ModelViewMap.map.getTransitionsMap().get(t);
			transitionView.paint(gc);
		}	
	}
	
	public abstract void paintFigure(GC gc);
	
	public void paintActivePoints(GC gc) {
		for (ActivePoint p : getActivePoints()) {
			p.paintActivePoint(gc);
		}
	}
	
	private List<ActivePoint> createActivePoints() {
		ResizeActivePoint topLeftPoint = new ResizeActivePoint() {
			@Override
			public Command perform() {
				if (!isNewResultsCorrect()) {
					return null;
				}
				//stateViewWidth = getNewWidth();
				//stateViewHeight = getNewHeight();
				//stateViewX = getTemporaryActivePointX();
				//stateViewY = getTemporaryActivePointY();
				
				return CommandFactory.createResizeStateCommand(
						StateView.this, 
						getTemporaryActivePointX(), 
						getTemporaryActivePointY(), 
						getNewWidth(), 
						getNewHeight());
			}
			@Override
			public Cursor createCursor() {
				return new Cursor(null, SWT.CURSOR_SIZENW);
			}
			@Override
			public int getNewWidth() {
				return stateViewWidth + stateViewX - getTemporaryActivePointX();
			}
			@Override
			public int getNewHeight() {
				return stateViewHeight + stateViewY - getTemporaryActivePointY();
			}
			@Override
			public int getCurrentActivePointX() {
				return stateViewX;
			}
			@Override
			public int getCurrentActivePointY() {
				return stateViewY;
			}
			@Override
			public Rectangle getTemporaryRectangle() {
				return new Rectangle(
						getTemporaryActivePointX(), 
						getTemporaryActivePointY(), 
						getNewWidth(), getNewHeight());
			}
		};
		
		ResizeActivePoint topRightPoint = new ResizeActivePoint() {
			@Override
			public Command perform() {
				if (!isNewResultsCorrect()) {
					return null;
				}
				return CommandFactory.createResizeStateCommand(
						StateView.this, 
						stateViewX, 
						getTemporaryActivePointY(), 
						getNewWidth(), 
						getNewHeight());
				//stateViewWidth = getNewWidth();
				//stateViewHeight = getNewHeight();
				//stateViewY = getTemporaryActivePointY();
				//return true;
			}
			@Override
			public Cursor createCursor() {
				return new Cursor(null, SWT.CURSOR_SIZENE);
			}
			@Override
			public int getNewWidth() {
				return getTemporaryActivePointX() - stateViewX;
			}
			@Override
			public int getNewHeight() {
				return stateViewHeight + stateViewY - getTemporaryActivePointY();
			}
			@Override
			public int getCurrentActivePointX() {
				return stateViewX + stateViewWidth;
			}
			@Override
			public int getCurrentActivePointY() {
				return stateViewY;
			}
			@Override
			public Rectangle getTemporaryRectangle() {
				return new Rectangle(
						stateViewX, getTemporaryActivePointY(), 
						getNewWidth(), getNewHeight());
			}	
		};
		
		ResizeActivePoint bottomLeftPoint = new ResizeActivePoint() {
			@Override
			public Command perform() {
				if (!isNewResultsCorrect()) {
					return null;
				}
				//stateViewWidth = getNewWidth();
				//stateViewHeight = getNewHeight();
				//stateViewX = getTemporaryActivePointX();
				//return true;
				return CommandFactory.createResizeStateCommand(
						StateView.this, 
						getTemporaryActivePointX(), 
						stateViewY, 
						getNewWidth(), 
						getNewHeight());
			}
			@Override
			public Cursor createCursor() {
				return new Cursor(null, SWT.CURSOR_SIZENE);
			}
			@Override
			public int getNewWidth() {
				return stateViewWidth + stateViewX - getTemporaryActivePointX();
			}
			@Override
			public int getNewHeight() {
				return getTemporaryActivePointY() - stateViewY;
			}
			@Override
			public int getCurrentActivePointX() {
				return stateViewX;
			}
			@Override
			public int getCurrentActivePointY() {
				return stateViewY + stateViewHeight;
			}
			@Override
			public Rectangle getTemporaryRectangle() {
				return new Rectangle(getTemporaryActivePointX(), stateViewY, 
						getNewWidth(), getNewHeight());
			}
		};
		
		ResizeActivePoint bottomRightPoint = new ResizeActivePoint() {
			@Override
			public Command perform() {
				if (!isNewResultsCorrect()) {
					return null;
				}
				//stateViewWidth = getNewWidth();
				//stateViewHeight = getNewHeight();
				//return true;
				return CommandFactory.createResizeStateCommand(
						StateView.this, 
						stateViewX, 
						stateViewY, 
						getNewWidth(), 
						getNewHeight());
			}
			@Override
			public Cursor createCursor() {
				return new Cursor(null, SWT.CURSOR_SIZENW);
			}
			@Override
			public int getNewWidth() {
				return getTemporaryActivePointX() - stateViewX;
			}
			@Override
			public int getNewHeight() {
				return getTemporaryActivePointY() - stateViewY;
			}
			@Override
			public int getCurrentActivePointX() {
				return stateViewX + stateViewWidth;
			}
			@Override
			public int getCurrentActivePointY() {
				return stateViewY + stateViewHeight;
			}
			@Override
			public Rectangle getTemporaryRectangle() {
				return new Rectangle(stateViewX, stateViewY, 
						getNewWidth(), getNewHeight());
			}
		};
		List<ActivePoint> points = new ArrayList<ActivePoint>(4);
		points.add(topLeftPoint);
		points.add(topRightPoint);
		points.add(bottomRightPoint);
		points.add(bottomLeftPoint);
		return points;
	}
	
	@Override
	public List<? extends ActivePoint> getActivePoints() {
		return points;
	}
}
